package com.utility;


import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class DBConnection 
{

	final static String url = "jdbc:mysql://localhost/";

	final static String dbName = "videolibrary";

	final static String driver = "com.mysql.jdbc.Driver";
	
	final static String userName = "root";

	final static String password = "sowmya1987"; 
	
	protected static List<PoolConnection> connections;
	
	protected static int MaxActiveConnections = 10;
	 
	public DBConnection()
	{
		connections =  new ArrayList<PoolConnection>();

		for(int i = 0; i< MaxActiveConnections ; i++)
		{
			try
			{
				Connection con = DriverManager.getConnection(url + dbName, userName,
						password);
			    PoolConnection pc = new PoolConnection(con);
				connections.add(pc);
				//System.out.println("created " + i + " connections");
			}
			catch(SQLException e)
			{
				e.printStackTrace();
			}
		}
	}
	  
	  protected static boolean checkConnections = true;

	  protected static long cleaningInterval =  30 * 1000; // 30 seconds
	  protected static long maxIdleTime = 30 * 1000; // 30 seconds

	  protected static long maxUseTime = -1; // disabled by default

	  protected static PoolCleaner cleaner;

	  public static Connection getConnection() throws SQLException
	  {
		  // Try reusing an existing Connection
		  synchronized (connections) {
			  PoolConnection pc = null;

			  for (int j = 0; j < connections.size(); j++) 
			  {
				  int i = (int) (Math.random() * MaxActiveConnections);
				  pc = connections.get(i);


				  //System.out.println("PoolConnection "+pc +" " +i+" is available");

				  if (pc.lease()) 
				  {

					  if (!checkConnections) 
					  {
						  return pc;
					  }
					  else {
						  // Check the status of the connection
						  boolean isHealthy = true;

						  try {
							  if (pc.isClosed() && pc.getWarnings() != null) 
							  {
								  isHealthy = false;
							  }
						  }
						  catch(SQLException sqle) {
							  // If we can't even ask for that information, we
							  // certainly don't want to use it anymore.
							  isHealthy = false;
						  }

						  if (isHealthy) 
						  {
							  return pc;
						  }
						  else 
						  {
							  try 
							  {
								  pc.expire();//
							  }
							  catch(SQLException sqle) 
							  {
								  // ignore
							  }
							  connections.remove(i);
						  }
					  }
				  }
			  }
		  }

		  // Create a new Connection
		  Connection con = DriverManager.getConnection(url + dbName, userName,
				  password);
		  System.out.println("Pool conn not available, creating new connection");
		  PoolConnection pc = new PoolConnection(con);
		  pc.lease();

		  synchronized (connections) 
		  {
			  connections.add(pc);
			  if (cleaner == null)
			  {
				  cleaner =  new PoolCleaner(30 * 1000);
				  cleaner.start();
			  }
		  }

		  return pc;
	  }
	  public static void removeExpired() {
		    PoolConnection pc;

		    long maxIdleDeadline = System.currentTimeMillis() - maxIdleTime;
		    long maxUseDeadline = System.currentTimeMillis() - maxUseTime;

		    synchronized (connections) 
		    {
		      // Check all connections
		      for (int i = connections.size() - 1; i >= 0; i--) 
		      {
		        pc = connections.get(i);
		        if (!pc.inUse() && pc.getTimeClosed() < maxIdleDeadline) 
		        {
		          connections.remove(i);
		          System.out.println("Connection has been idle for too long... closing conenction " +i);
		          try 
		          {
		            pc.expire();
		          }
		          catch (SQLException ignore) {
		          }
		        }
		        else if (
		          maxUseTime >= 0 && // don't check if disabled
		          pc.inUse() &&
		          pc.getTimeOpened() < maxUseDeadline)
		        {
		          System.err.println("Warning: forced closing of a connection that has been in use too long.");
		          System.err.println("Connection was acquired in:");
		          pc.printStackTrace();
		          System.err.println();

		          connections.remove(i);
		          try {
		            pc.expire();
		          }
		          catch (SQLException ignore) {
		          }
		        }
		      }

		      if (connections.size() == 0 && cleaner != null) {
		        cleaner.halt();
		        cleaner = null;
		      }
		    }
		  }
	  
	  static class PoolCleaner extends Thread {

		    protected long _cleaningInterval;
		    protected boolean _mustStop;

		    public PoolCleaner(long cleaningInterval) {
		      if (cleaningInterval < 0) {
		        throw new IllegalArgumentException("cleaningInterval must be >= 0");
		      }
		      _mustStop = false;
		      _cleaningInterval = cleaningInterval;

		      setDaemon(true);
		    }

		    public void run() {
		      while (!_mustStop) {
		        try {
		          sleep(_cleaningInterval);
		        }
		        catch (InterruptedException ignore) {
		        }

		        if (_mustStop) {
		          break;
		        }

		        removeExpired();
		      }
		    }

		    public void halt() {
		      _mustStop = true;
		      synchronized (this) {
		        this.interrupt();
		      }
		    }
		  }
	  static class PoolConnection implements Connection 
	  {
		    protected Connection conn;

		    protected boolean inUse;

		    protected boolean autoCommit;

		    protected long timeOpened;

		    protected long timeClosed;

		    private Throwable throwable;


		    public PoolConnection(Connection con) {
		      conn = con;
		      inUse = false;
		      autoCommit = true;
		    }

		    public synchronized boolean lease() {
		      if (inUse) {
		        return false;
		      }
		      else {
		        inUse = true;
		        timeOpened = System.currentTimeMillis();
		        return true;
		      }
		    }

		    /**
		     * Checks if the connection currently is used by someone.
		     **/
		    public boolean inUse() {
		      return inUse;
		    }

		    /**
		     * Returns the time stamp of the last time this connection was
		     * opened/leased.
		     **/
		    public synchronized long getTimeOpened() {
		      return timeOpened;
		    }

		    /**
		     * Returns the time stamp of the last time this connection was
		     * closed.
		     **/
		    public synchronized long getTimeClosed() {
		      return timeClosed;
		    }

		    /**
		     * Expires this connection and closes the underlying connection to the
		     * database. Once expired, a connection can no longer be used.
		     **/
		    public void expire()
		      throws SQLException
		    {
		      conn.close();
		      conn = null;
		    }

		    public void printStackTrace() {
		      throwable.printStackTrace(System.err);
		    }

		    public synchronized void close()
		      throws SQLException
		    {
		      // Multiple calls to close?
		      if (inUse) {
		        timeClosed = System.currentTimeMillis();
		        inUse = false;

		        if (autoCommit == false) 
		        {
		          setAutoCommit(true);
		        }
		      }
		    }

		    public Statement createStatement()
		      throws SQLException
		    {
		      throwable = new Throwable();
		      return conn.createStatement();
		    }

		    public PreparedStatement prepareStatement(String sql)
		      throws SQLException
		    {
		      throwable = new Throwable();
		      return conn.prepareStatement(sql);
		    }

		    public CallableStatement prepareCall(String sql)
		      throws SQLException
		    {
		      return conn.prepareCall(sql);
		    }

		    public String nativeSQL(String sql)
		      throws SQLException
		    {
		      return conn.nativeSQL(sql);
		    }

		    public void setAutoCommit(boolean autoCommit)
		      throws SQLException
		    {
		      conn.setAutoCommit(autoCommit);
		      autoCommit = conn.getAutoCommit();
		    }

		    public boolean getAutoCommit()
		      throws SQLException
		    {
		      return conn.getAutoCommit();
		    }

		    public void commit()
		      throws SQLException
		    {
		      conn.commit();
		    }

		    public void rollback()
		      throws SQLException
		    {
		      conn.rollback();
		    }

		    public boolean isClosed()
		      throws SQLException
		    {
		      return conn.isClosed();
		    }

		    public DatabaseMetaData getMetaData()
		      throws SQLException
		    {
		      return conn.getMetaData();
		    }

		    public void setReadOnly(boolean readOnly)
		      throws SQLException
		    {
		      conn.setReadOnly(readOnly);
		    }

		    public boolean isReadOnly()
		      throws SQLException
		    {
		      return conn.isReadOnly();
		    }

		    public void setCatalog(String catalog)
		      throws SQLException
		    {
		      conn.setCatalog(catalog);
		    }

		    public String getCatalog()
		      throws SQLException
		    {
		      return conn.getCatalog();
		    }

		    public void setTransactionIsolation(int level)
		      throws SQLException
		    {
		      conn.setTransactionIsolation(level);
		    }

		    public int getTransactionIsolation()
		      throws SQLException
		    {
		      return conn.getTransactionIsolation();
		    }

		    public SQLWarning getWarnings()
		      throws SQLException
		    {
		      return conn.getWarnings();
		    }

		    public void clearWarnings()
		      throws SQLException
		    {
		      conn.clearWarnings();
		    }

		    public Statement createStatement(
		      int resultSetType, int resultSetConcurrency)
		      throws SQLException
		    {
		      return conn.createStatement(resultSetType, resultSetConcurrency);
		    }

		    public PreparedStatement prepareStatement(
		      String sql, int resultSetType, int resultSetConcurrency)
		      throws SQLException
		    {
		      return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
		    }

		    public CallableStatement prepareCall(
		      String sql, int resultSetType, int resultSetConcurrency)
		      throws SQLException
		    {
		      return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
		    }

		    public Map<String,Class<?>> getTypeMap()
		      throws SQLException
		    {
		      return conn.getTypeMap();
		    }

		    public void setTypeMap(Map<String,Class<?>> map)
		      throws SQLException
		    {
		      conn.setTypeMap(map);
		    }

		    public void setHoldability(int holdability)
		      throws SQLException
		    {
		      conn.setHoldability(holdability);
		    }

		    public int getHoldability()
		      throws SQLException
		    {
		      return conn.getHoldability();
		    }

		    public Savepoint setSavepoint()
		      throws SQLException
		    {
		      return conn.setSavepoint();
		    }

		    public Savepoint setSavepoint(String name)
		      throws SQLException
		    {
		      return conn.setSavepoint(name);
		    }

		    public void rollback(Savepoint savepoint)
		      throws SQLException
		    {
		      conn.rollback(savepoint);
		    }

		    public void releaseSavepoint(Savepoint savepoint)
		      throws SQLException
		    {
		      conn.releaseSavepoint(savepoint);
		    }

		    public Statement createStatement(
		        int resultSetType,
		        int resultSetConcurrency,
		        int resultSetHoldability)
		      throws SQLException
		    {
		      return conn.createStatement(
		        resultSetType, resultSetConcurrency, resultSetHoldability);
		    }

		    public PreparedStatement prepareStatement(
		        String sql,
		        int resultSetType,
		        int resultSetConcurrency,
		        int resultSetHoldability)
		      throws SQLException
		    {
		      return conn.prepareStatement(
		        sql, resultSetType, resultSetConcurrency, resultSetHoldability);
		    }

		    public CallableStatement prepareCall(
		        String sql,
		        int resultSetType,
		        int resultSetConcurrency,
		        int resultSetHoldability)
		      throws SQLException
		    {
		      return conn.prepareCall(
		        sql, resultSetType, resultSetConcurrency, resultSetHoldability);
		    }

		    public PreparedStatement prepareStatement(
		        String sql, int autoGenerateKeys)
		      throws SQLException
		    {
		      return conn.prepareStatement(sql, autoGenerateKeys);
		    }

		    public PreparedStatement prepareStatement(
		        String sql, int[] columnIndexes)
		      throws SQLException
		    {
		      return conn.prepareStatement(sql, columnIndexes);
		    }

		    public PreparedStatement prepareStatement(
		        String sql, String[] columnNames)
		      throws SQLException
		    {
		      return conn.prepareStatement(sql, columnNames);
		    }

		    public Clob createClob() throws SQLException {
		      // TODO Auto-generated method stub
		      return null;
		    }

		    public Blob createBlob() throws SQLException {
		      // TODO Auto-generated method stub
		      return null;
		    }

		    public NClob createNClob() throws SQLException {
		      // TODO Auto-generated method stub
		      return null;
		    }

		    public SQLXML createSQLXML() throws SQLException {
		      // TODO Auto-generated method stub
		      return null;
		    }

		    public boolean isValid(int timeout) throws SQLException {
		      // TODO Auto-generated method stub
		      return false;
		    }

		    public void setClientInfo(String name, String value) throws SQLClientInfoException {
		      // TODO Auto-generated method stub
		      
		    }

		    public void setClientInfo(Properties properties) throws SQLClientInfoException {
		      // TODO Auto-generated method stub
		      
		    }

		    public String getClientInfo(String name) throws SQLException {
		      // TODO Auto-generated method stub
		      return null;
		    }

		    public Properties getClientInfo() throws SQLException {
		      // TODO Auto-generated method stub
		      return null;
		    }

		    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
		      // TODO Auto-generated method stub
		      return null;
		    }

		    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
		      // TODO Auto-generated method stub
		      return null;
		    }

		    public <T> T unwrap(Class<T> iface) throws SQLException {
		      // TODO Auto-generated method stub
		      return null;
		    }

		    public boolean isWrapperFor(Class<?> iface) throws SQLException {
		      // TODO Auto-generated method stub
		      return false;
		    }
		  }

}



